//
//  YZMKLineView.m
//  YZMicroStock
//
//  Created by wangminhong on 16/4/12.
//  Copyright © 2016年 cqjr. All rights reserved.
//

#import "YZMKLineView.h"
#import "YZMQuoteStyle.h"
#import "YZMKLinePacket.h"
#import "YZMKLineItem.h"
#import <DateTools/DateTools.h>
#import "NSString+Utils.h"

#define SCALESTEXTHEIGHT 16
#define DEFAUTSTARTINDEX 0


@interface YZMKLineView ()
{
    NSInteger _currentIndex;
}

@property (nonatomic, strong) NSMutableArray *timeIndexs;

@end

@implementation YZMKLineView{
    
    NSInteger _candyWidth;
    NSInteger _candySeparator;
    NSInteger _startIndex;
    NSInteger _basicIndex;
}


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame: frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.timeIndexs  = [NSMutableArray array];
        self.styleDict = [YZMQuoteStyle klineStyleDict];
        _candySeparator = 3;
        _candyWidth = 3;
        _startIndex = DEFAUTSTARTINDEX;
        
        _currentIndex = -1;
    }
    return self;
}


#pragma mark - drawing

- (CGFloat)offsetOfIndex: (NSInteger)index inRect: (CGRect)rect
{
    NSInteger candleCost = _candyWidth + _candySeparator;
    NSInteger startOffset = rect.origin.x +  _candySeparator;
    if (index < _startIndex) {
        return startOffset;
    }
    return startOffset + candleCost * (index-_startIndex);
}

- (NSInteger)indexOfOffset: (CGFloat)offset inRect: (CGRect)rect
{
    if (offset < 0 || offset > rect.size.width) {
        return NSNotFound;
    }
    NSInteger candleCost = _candyWidth + _candySeparator;
    NSInteger allow = rect.size.width / candleCost;
    NSInteger index = offset / candleCost;
    if (index < allow) {
        return index;
    }
    else
    {
        return allow-1;
    }
}


- (NSInteger)allowCountFitWith
{
    CGFloat divideHeight = (self.bounds.size.height - 25) * 2 / 3;
    CGFloat chartWidth = self.bounds.size.width - 30;
    CGRect priceRect = CGRectMake(15, 0, chartWidth, divideHeight);
    NSInteger candyCost = _candyWidth + _candySeparator;
    NSInteger allow = priceRect.size.width / candyCost;
    return allow;
}


- (void)setDrawColorForPoint: (YZMKLinePoint *)point inContext: (CGContextRef)context
{
    if (point.rise) {
        UIColor *riseColor = self.styleDict[KLINE_RISE_COLOR_KEY];
        CGContextSetStrokeColorWithColor(context, riseColor.CGColor);
        CGContextSetFillColorWithColor(context, riseColor.CGColor);
    }
    else
    {
        UIColor *fallColor = self.styleDict[KLINE_FALL_COLOR_KEY];
        CGContextSetStrokeColorWithColor(context, fallColor.CGColor);
        CGContextSetFillColorWithColor(context, fallColor.CGColor);
    }
}

- (void)drawDayCandleInRect: (CGRect)rect startIndex: (NSInteger)startIndex inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    CGFloat xOffset = 0;
    
    
    NSInteger candleCost = _candyWidth + _candySeparator;
    NSInteger allow = rect.size.width / candleCost;
    NSInteger startOffset = rect.origin.x +  _candySeparator;
    
    
    for (NSInteger i = startIndex; i < self.dataArray.count && i < _startIndex + allow; i++) {
        YZMKLinePoint *point = self.dataArray[i];
        xOffset = startOffset + candleCost * (i - startIndex);
        CGFloat top = rect.origin.y + point.open * rect.size.height;
        CGFloat candyHeight = (point.close-point.open) * rect.size.height;
        CGRect candleRect = CGRectMake(xOffset, top, _candyWidth, candyHeight);
        
        [self setDrawColorForPoint: point inContext: context];
        
        CGContextStrokeRect(context, candleRect);
        CGContextFillRect(context, candleRect);
        
        
        CGFloat lineTop = rect.origin.y + point.highest * rect.size.height;
        CGFloat lineBottom = rect.origin.y + point.lowest * rect.size.height;
        CGContextMoveToPoint(context, xOffset + _candyWidth / 2, lineTop);
        CGContextAddLineToPoint(context, xOffset + _candyWidth / 2, lineBottom);
        CGContextStrokePath(context);
        
    }
    
    CGContextRestoreGState(context);
}

- (void)drawAmountInRect: (CGRect)rect startIndex: (NSInteger)startIndex inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    CGFloat xOffset = 0;
    
    NSInteger candleCost = _candyWidth + _candySeparator;
    NSInteger allow = rect.size.width / candleCost;
    NSInteger startOffset = rect.origin.x +  _candySeparator;
    
    
    for (NSInteger i = startIndex; i < self.dataArray.count && i < startIndex + allow; i++) {
        YZMKLinePoint *point = self.dataArray[i];
        xOffset = startOffset + candleCost * (i - startIndex);
        CGFloat top = rect.origin.y + point.amount * rect.size.height;
        CGFloat amountHeight = rect.size.height - point.amount * rect.size.height;
        CGRect amountRect = CGRectMake(xOffset, top, _candyWidth, amountHeight);
        
        [self setDrawColorForPoint: point inContext: context];
        
        CGContextStrokeRect(context, amountRect);
        CGContextFillRect(context, amountRect);
        
    }
    
    
    
    CGContextRestoreGState(context);
}


- (void)drawAvergeLineInRect: (CGRect)rect startIndex: (NSInteger)startIndex forEnum: (CGFloat (^)(id obj))enumPoint lineStart: (NSInteger)lineIndex  inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    CGFloat xOffset = 0;
    CGFloat yOffset = 0;
    
    
    NSInteger candyCost = _candyWidth + _candySeparator;
    NSInteger allow = rect.size.width / candyCost;
    NSInteger startOffset = rect.origin.x + _candySeparator;
    
    BOOL firstPoint = YES;
    for (NSInteger i = startIndex; i < self.dataArray.count && i < startIndex + allow; i++) {
        
        //判断是否空线
        if (i + self.basicIndex < lineIndex) {
            continue;
        }
        
        YZMKLinePoint *point = self.dataArray[i];
        
        xOffset = startOffset + candyCost * (i - startIndex) + _candyWidth / 2;
        CGFloat value = enumPoint(point);
        yOffset = rect.origin.y + rect.size.height * value;
        
        if (firstPoint) {
            CGContextMoveToPoint(context, xOffset, yOffset);
            firstPoint = NO;
        }
        else
        {
            CGContextAddLineToPoint(context, xOffset, yOffset);
        }
        
    }
    
    CGContextStrokePath(context);
    
    CGContextRestoreGState(context);
}

- (void)drawAvgLinesStartIndex: (NSInteger)startIndex InRect: (CGRect)rect inContext: (CGContextRef)context
{
    
    UIColor *tempColor = self.styleDict[KLINE_AVERGE1_COLOR_KEY];
    [tempColor setStroke];
    [self drawAvergeLineInRect: rect startIndex: startIndex forEnum:^CGFloat(YZMKLinePoint *obj) {
        return [(NSNumber *)obj.avgPoints[0] floatValue];
    } lineStart: 4 inContext: context];
    
    tempColor = self.styleDict[KLINE_AVERGE2_COLOR_KEY];
    [tempColor setStroke];
    [self drawAvergeLineInRect: rect startIndex: startIndex forEnum:^CGFloat(YZMKLinePoint *obj) {
        return [(NSNumber *)obj.avgPoints[1] floatValue];
    } lineStart: 9 inContext: context];
    
    tempColor = self.styleDict[KLINE_AVERGE3_COLOR_KEY];
    [tempColor setStroke];
    [self drawAvergeLineInRect: rect startIndex: startIndex forEnum:^CGFloat(YZMKLinePoint *obj) {
        return [(NSNumber *)obj.avgPoints[2] floatValue];
    } lineStart: 19 inContext: context];
    
    tempColor = self.styleDict[KLINE_AVERGE4_COLOR_KEY];
    [tempColor setStroke];
    [self drawAvergeLineInRect: rect startIndex: startIndex forEnum:^CGFloat(YZMKLinePoint *obj) {
        return [(NSNumber *)obj.avgPoints[3] floatValue];
    } lineStart: 29 inContext: context];
}

- (void)drawPriceBoundsInRect:(CGRect)rect inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    UIColor *borderColor = self.styleDict[CHAR_BOUND_COLOR_KEY];
    [borderColor setStroke];
    CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));
    
    for (int i = 1; i < 4; i++) {
        CGFloat yOffset = rect.origin.y + rect.size.height * i / 4;
        yOffset = (int)yOffset+0.5;
        
        CGContextMoveToPoint(context, rect.origin.x, yOffset);
        CGContextAddLineToPoint(context, rect.origin.x+rect.size.width, yOffset);
    }
    
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

- (void)drawVolumeBoundsInRect:(CGRect)rect inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    CGFloat lineOffset = .5;
    UIColor *borderColor = self.styleDict[CHAR_BOUND_COLOR_KEY];
    [borderColor setStroke];
    CGContextStrokeRect(context, CGRectInset(rect, lineOffset, lineOffset));
    
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

- (void)drawMontheLinesInRect:(CGRect)rect inContext: (CGContextRef)context
{
    NSInteger count = self.timeIndexs.count;
    NSInteger totalLine = ceil([self allowCountFitWith] / 9.0);
    if (count > 2) {
        for (NSInteger i = 1; i < count; i++) {
            YZMKLinePoint *point = self.timeIndexs[i];
            NSInteger index = [self.dataArray indexOfObject: point];
            if (index != NSNotFound && totalLine != i + 1) {
                CGFloat offset = [self offsetOfIndex: index inRect: rect];
                CGContextMoveToPoint(context, offset, rect.origin.y);
                CGContextAddLineToPoint(context, offset, rect.origin.y+rect.size.height);
            }
        }
        CGContextStrokePath(context);
    }
}

- (void)drawTimesExInRect: (CGRect)rect inContext: (CGContextRef)context
{
    NSInteger count = self.dataArray.count;
    CGFloat preUsed = rect.origin.x-1;
    UIFont *font = [UIFont systemFontOfSize: 12];
    UIColor *textColor = [YZMAppStyle colorForMainTextColor];
    NSInteger allow  = [self allowCountFitWith];
    for (NSInteger i = 0; i < self.timeIndexs.count; i++) {
        YZMKLinePoint *pointObj = self.timeIndexs[i];
        NSInteger index = [self.dataArray indexOfObject: pointObj];
        if (index == NSNotFound || index > _startIndex+allow) {
            continue;
        }
        
        NSString *str = [pointObj timeStr];
        
        CGFloat length = [str yz_sizeWithFont: font].width;
        CGPoint point = CGPointZero;
        point.y = rect.origin.y;
        
        if (index == 0) {
            point.x = rect.origin.x;
        }
        else if (index == count-1)
        {
            point.x = rect.origin.x+rect.size.width-length;
        }
        else
        {
            CGFloat offset = [self offsetOfIndex: index inRect: rect];
//            point.x = offset - length;
            point.x = offset;
        }
        
        //TODO: draw cover advoice
        if (point.x > preUsed) {
            [str yz_drawAtPoint: point withFont: font color:textColor];
            preUsed = point.x+length;
        }
        
        
    }
    CGContextStrokePath(context);
}

//时间
- (void)drawTimesInRect: (CGRect)rect inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    
    UIColor *tempColor = self.styleDict[TREND_TIME_COLOR];
    [tempColor setStroke];
    [tempColor setFill];
    
    NSInteger count = self.dataArray.count;
    NSInteger timeIndexs[] = {0, count-1};
    NSInteger length = sizeof(timeIndexs)/sizeof(NSInteger);
    
    CGFloat preUsed = rect.origin.x-1;
    
    UIFont *font = [UIFont systemFontOfSize: 12];
    for (NSInteger i = 0; i < length; i++) {
        NSInteger index = timeIndexs[i];
        if (index < 0 || index >= count) {
            continue;
        }
        YZMKLinePoint *pointObj = self.dataArray[index];
        
        NSString *str = [pointObj timeStr];
        
        CGFloat length = [str yz_sizeWithFont: font].width;
        CGPoint point = CGPointZero;
        point.y = rect.origin.y;
        
        if (index == 0) {
            point.x = rect.origin.x;
        }
        else if (index == count-1)
        {
            point.x = rect.origin.x+rect.size.width-length;
        }
        else
        {
            CGFloat offset = [self offsetOfIndex: index inRect: rect];
            point.x = offset + length/2;
        }
        
        //TODO: draw cover advoice
        if (point.x > preUsed) {
            [str yz_drawAtPoint: point withFont: font];
        }
        
        preUsed = point.x+length;
    }
    CGContextRestoreGState(context);
}

- (void)drawVerticalScales: (NSArray *)scales rightAlign: (BOOL)isRight inRect: (CGRect)rect inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    NSInteger count = scales.count;
    CGFloat separa = rect.size.height / (count+1);
    CGFloat textHeight = SCALESTEXTHEIGHT;
    UIColor *textColor = self.styleDict[FOCUS_TEXT_COLOR_KEY];
    for (int i = 0; i < count; i++) {
        CGFloat moved = -SCALESTEXTHEIGHT+3;
        CGRect textRect = CGRectMake(rect.origin.x + (isRight ? -2 : 2), rect.origin.y + separa * (i+1) + moved, rect.size.width, textHeight);
        
        NSString *text = scales[i];
        [text yz_drawInRect: textRect withFont: [UIFont systemFontOfSize: 10] lineBreakMode: NSLineBreakByClipping alignment: isRight?NSTextAlignmentRight : NSTextAlignmentLeft color:textColor];
        
    }
    CGContextRestoreGState(context);
}


//标度
- (void)drawScalesInRect: (CGRect)rect inContext: (CGContextRef)context
{
    NSString *topString = [NSString stringWithFormat: @"%.2f", (self.maxPrice - self.minPrice)*0.75 + self.minPrice];
    NSString *midString = [NSString stringWithFormat: @"%.2f", (self.maxPrice+self.minPrice)/2];
    NSString *bottomString = [NSString stringWithFormat: @"%.2f", (self.maxPrice - self.minPrice)*0.25 + self.minPrice];
    [self drawVerticalScales: @[topString, midString, bottomString] rightAlign: YES inRect: rect inContext: context];
}

- (void)drawVolumeScalesinRect: (CGRect)rect inContext: (CGContextRef)context
{
    NSString *topString = [NSString stringWithFormat: @"%ld", (long)self.maxAmount];
    [self drawVerticalScales: @[topString, @""] rightAlign: NO inRect:rect inContext: context];
}

- (void)drawCurrentDataInRect: (CGRect)rect inContext: (CGContextRef)context
{
    CGContextSaveGState(context);
    CGRect backRect = CGRectMake(rect.origin.x, rect.origin.y, 80, 100);
    CGFloat xOffset = [self offsetOfIndex: _currentIndex inRect:rect];
    if (xOffset < rect.origin.x + rect.size.width/2) {
        backRect = CGRectOffset(backRect, rect.size.width-backRect.size.width, 0);
    }
    
    UIColor *tempColor = self.styleDict[FOCUS_LINE_COLOR_KEY];
    [tempColor setStroke];
    CGContextStrokeRect(context, backRect);
    tempColor = self.styleDict[FOCUS_BACK_COLOR_KEY];
    [tempColor setFill];
    CGContextFillRect(context, backRect);
    NSString *openPrice = [NSString stringWithFormat: @"开:%.2f", self.currentItem.open];
    NSString *closePrice = [NSString stringWithFormat: @"收:%.2f", self.currentItem.price];
    NSString *highPrice = [NSString stringWithFormat: @"量:%.2f", self.currentItem.high];
    NSString *lowestPrice = [NSString stringWithFormat: @"量:%.2f", self.currentItem.low];
    
    NSString *amount = [NSString stringWithFormat: @"量:%.0f", self.currentItem.volume/100];
    NSArray *tempArray = @[openPrice, closePrice, highPrice, lowestPrice, amount];
    
    tempColor = self.styleDict[FOCUS_TEXT_COLOR_KEY];
    [tempColor setFill];
    for (int i = 0; i < [tempArray count]; i++) {
        NSString *drawStr = tempArray[i];
        CGRect strRect = CGRectOffset(backRect, 2, i * 20);
        [drawStr yz_drawInRect: strRect withFont: [UIFont systemFontOfSize: 15] lineBreakMode: NSLineBreakByClipping];
    }
    
    tempColor = self.styleDict[FOCUS_LINE_COLOR_KEY];
    [tempColor setStroke];
    if (xOffset > backRect.origin.x && xOffset < backRect.origin.x + backRect.size.width) {
        CGContextMoveToPoint(context, xOffset, rect.origin.y + backRect.size.height);
    }
    else
    {
        CGContextMoveToPoint(context, xOffset, rect.origin.y);
    }
    
    CGContextAddLineToPoint(context, xOffset, rect.origin.y+rect.size.height);
    
    YZMKLinePoint *item = self.dataArray[_currentIndex];
    CGFloat yOffset = rect.origin.y + rect.size.height /2 + rect.size.height/2 * item.close;
    if (yOffset > backRect.origin.y+backRect.size.height) {
        CGContextMoveToPoint(context, rect.origin.x, yOffset);
        CGContextAddLineToPoint(context, rect.origin.x+rect.size.width, yOffset);
    }
    else if (xOffset < rect.origin.x + rect.size.width/2) {
        CGContextMoveToPoint(context, rect.origin.x, yOffset);
        CGContextAddLineToPoint(context, backRect.origin.x, yOffset);
    }
    else
    {
        CGContextMoveToPoint(context, backRect.origin.x+backRect.size.width, yOffset);
        CGContextAddLineToPoint(context, rect.origin.x+rect.size.width, yOffset);
    }
    CGContextStrokePath(context);
    CGContextRestoreGState(context);
}

- (void)drawCurrentAmountInRect: (CGRect)rect inContext: (CGContextRef)context
{
    CGFloat xOffset = [self offsetOfIndex: _currentIndex inRect:rect];
    CGContextMoveToPoint(context, xOffset, rect.origin.y);
    CGContextAddLineToPoint(context, xOffset, rect.origin.y+rect.size.height);
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    //边框设置
    CGFloat divideHeight = (rect.size.height - 25) * 2 / 3;
    CGFloat chartWidth = rect.size.width - 30;
    CGRect priceRect = CGRectMake(15, 0, chartWidth, divideHeight);
    CGRect timeRect = CGRectMake(15, divideHeight, chartWidth, 20);
    CGRect amountRect = CGRectMake(15, divideHeight+20, chartWidth, divideHeight / 2);
    
    NSInteger startIndex = _startIndex;
    if (startIndex >= self.dataArray.count) {
        NSInteger allow = [self allowCountFitWith];
        startIndex = self.dataArray.count - allow;
        if (startIndex < 0) {
            startIndex = 0;
        }
    }
    
    UIColor *boundsColor = self.styleDict[CHAR_BOUND_COLOR_KEY];
    [boundsColor setStroke];
    
    [self drawMontheLinesInRect: priceRect inContext: context];
    [self drawMontheLinesInRect: amountRect  inContext: context];
    
    [self drawPriceBoundsInRect: priceRect inContext: context];
    [self drawVolumeBoundsInRect: amountRect inContext: context];
    
    [self drawDayCandleInRect: priceRect startIndex: startIndex inContext: context];
    
    [self drawAmountInRect: amountRect startIndex: startIndex inContext: context];
    
    [self drawTimesExInRect:timeRect inContext: context];
//    [self drawTimesInRect: timeRect inContext: context];
    
    [self drawAvgLinesStartIndex: startIndex InRect: priceRect inContext: context];
    
    [boundsColor setFill];
    [self drawScalesInRect: priceRect inContext: context];
//    [self drawVolumeScalesinRect: amountRect inContext: context];
    
    if (_currentIndex > -1)
    {
        [self drawCurrentDataInRect: priceRect inContext: context];
        [self drawCurrentAmountInRect: amountRect inContext: context];
    }
}

- (void)_updateTimeIndexs
{
    [self.timeIndexs removeAllObjects];
    NSInteger count = self.dataArray.count;
    if (count == 0) {
        return;
    }
//    YZMKLinePoint *firstPoint = self.dataArray[0];
//    [self.timeIndexs addObject: firstPoint];
    NSInteger spaceIndex = 9;/*间隔显示时间*/
    NSInteger strCount = ceil(self.dataArray.count*1.0/spaceIndex);
//    NSDate *previousDate = nil;
//    YZMKLinePoint *previousPoint = nil;
    for (NSInteger i = 0; i < strCount; i++) {
        YZMKLinePoint *point = self.dataArray[i*spaceIndex];
//        NSDate *current = [NSDate dateWithTimeIntervalSince1970: point.time/1000.0];
//        if (i > 1) {
//            if (current.month > previousDate.month) {
                [self.timeIndexs addObject: point];
//            }
//        }
//        previousPoint = point;
//        previousDate = current;
    }
//    if (count > 1) {
//        [self.timeIndexs addObject: self.dataArray.lastObject];
//    }
}

- (void)updateFromDataPacket: (YZMKLinePacket *)packet
{
    
    NSInteger allow = [self allowCountFitWith];
    packet.windowCount = allow;
    _basicIndex = packet.itemCount-allow;
    if (_basicIndex < 0) {
        _basicIndex = 0;
    }
    packet.basicIndex = _basicIndex;
    _startIndex = DEFAUTSTARTINDEX;
    
    self.dataArray = [packet klineDrawPoints];
    self.maxPrice = packet.maxPrice;
    self.minPrice = packet.minPrice;
    self.maxAmount = packet.maxVolume;
    [self _updateTimeIndexs];
    
    [self setNeedsDisplay];
}

- (void)clearData
{
    self.dataArray = nil;
    self.maxPrice = 0;
    self.minPrice = 0;
    self.maxAmount = 0;
    
    _startIndex = DEFAUTSTARTINDEX;
    
    [self setNeedsDisplay];
}



@end
